#ifndef _RETRO_PLAYER_SPRITE
#define _RETRO_PLAYER_SPRITE

#include "player.graphic.h"

namespace Retro
{
  namespace Player
  {
    namespace HitTest
    {
      struct HitTestData;
    }

    namespace Graphic
    {
      enum Direction
      {
        DirectionNone,
        DirectionLeft,
        DirectionRight,
        DirectionUp,
        DirectionDown,
      };

      enum SpritePart
      {
        SpriteFull,
        SpriteBody,
        SpriteHead,
      };

      struct Sprite
      {
        Geom::Bounds  bounds;
        Geom::Bounds  bbox;
        Vector2D      vel;
        UINT          index;
        UINT          frame;
        Direction     dir;
      };

      class SpriteSet : public IGraphic
      {
      private:
        Display::Texture* mTexture;

        UINT  mSpriteSize;
        UINT  mFrames;

        VOID  getSource(const Sprite* iSprite, Geom::Bounds& oSource) const;

      public:
        virtual VOID init(Display::DisplayDevice* iDevice);
        virtual VOID uninit(Display::DisplayDevice* iDevice);

        INL Display::Texture* getTexture() const
        {
          return mTexture;
        }

        INL VOID setTexture(Display::Texture* iValue)
        {
          if (mTexture)
            mTexture->unref();

          if (mTexture = iValue)
            mTexture->ref();
        }

        INL UINT getSpriteSize() const
        {
          return mSpriteSize;
        }

        INL VOID setSpriteSize(UINT iValue)
        {
          mSpriteSize = iValue;
        }

        INL UINT getFrameCount() const
        {
          return mFrames;
        }

        INL VOID setFrameCount(UINT iValue)
        {
          mFrames = iValue;
        }

        BOOL  render(
          Display::DisplayDevice* iDevice,
          const Sprite* iSprite,
          const Geom::Point& iOffset,
          SpritePart iPart
          ) const;

        SpriteSet();
        ~SpriteSet();
      };

      class SpriteBuffer : public IGraphic
      {
      private:
        Generic::Vector<Sprite, 500> mBuffer;

      public:
        virtual VOID init(Display::DisplayDevice* iDevice);
        virtual VOID uninit(Display::DisplayDevice* iDevice);

        BOOL  render(
          Display::DisplayDevice* iDevice,
          const Geom::Point& iOffset,
          const SpriteSet* iSpriteSet,
          UINT iStart,
          UINT iEnd,
          SpritePart iPart
          ) const;

        INT   hitTestSprite(
          UINT iIndex,
          HitTest::HitTestData& oData
          );

        INT   hitTestMap(
          UINT iIndex,
          const Data::GridMap* iMap,
          UINT iLayer,
          HitTest::HitTestData& oData
          );

        INL VOID setSize(UINT iValue)
        {
          mBuffer.setSize(iValue);
        }

        INL UINT getSize() const
        {
          return mBuffer.getSize();
        }

        INL Sprite& getSprite(UINT iIndex)
        {
          return mBuffer[iIndex];
        }

        INL const Sprite& getSprite(UINT iIndex) const
        {
          return mBuffer[iIndex];
        }

        SpriteBuffer();
      };
    }
  }
}

#endif